/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * *
 *            Copyright (C) 2018 Institute of Computing Technology, CAS
 *               Author : Han Shukai (email : hanshukai@ict.ac.cn)
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * *
 *                  The shell acts as a task running in user mode.
 *       The main function is to make system calls through the user's output.
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * *
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify,
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *  * * * * * * * * * * */

#include <test3.h>
#include <string.h>
#include <os.h>
#include <sys/syscall.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
extern void test_affinity();
struct task_info task_test_waitpid = {
    (uintptr_t)&wait_exit_task, USER_PROCESS};
struct task_info task_test_semaphore = {
    (uintptr_t)&semaphore_add_task1, USER_PROCESS};
struct task_info task_test_condition = {
    (uintptr_t)&test_condition, USER_PROCESS};
struct task_info task_test_barrier = {
    (uintptr_t)&test_barrier, USER_PROCESS};
struct task_info task_test_affintiy = {
    (uintptr_t)&test_affinity,USER_PROCESS
};

struct task_info task13 = {(uintptr_t)&SunQuan, USER_PROCESS};
struct task_info task14 = {(uintptr_t)&LiuBei, USER_PROCESS};
struct task_info task15 = {(uintptr_t)&CaoCao, USER_PROCESS};
struct task_info task_test_multicore = {(uintptr_t)&test_multicore, USER_PROCESS};

static struct task_info *test_tasks[16] = {&task_test_waitpid,
                                           &task_test_semaphore,
                                           &task_test_condition,
                                           &task_test_barrier,
                                           &task13, &task14, &task15,
                                           &task_test_multicore,&task_test_affintiy};
static int num_test_tasks = 8;

#define SHELL_BEGIN 25
void cmd_op(int argc, char argv[][20])
{
    if(argc == 1){
        if(strcmp(argv[0], "ps")==0)
            sys_ps();
        else if(strcmp(argv[0], "clear")==0){
            sys_screen_clear();
            sys_move_cursor(1, 20);
            printf("-------------------- COMMAND --------------------\n");
        }
        else if(strcmp(argv[0], "exit")==0)
            sys_exit();
        else
            printf("Unknown command!\n");
    }
    else if(argc == 2){
        int pid = 0;
        int i=0;
        while(argv[1][i]!=' '&& argv[1][i]!='\0'){
            pid=pid*10+argv[1][i]-'0';
            i++;
        }
        if(strcmp(argv[0], "exec")==0)
        {
            sys_spawn(test_tasks[pid],NULL,ENTER_ZOMBIE_ON_EXIT);
            printf("spawn process[%d]\n", pid);
        }
        else if(strcmp(argv[0], "kill")==0)
        {
            sys_kill(pid);
            printf("kill process pid = %d\n", pid);
        }
        else
            printf("Unknown command!\n");
    }else if(argc == 3){
        int mask = 0;
        int i=0;
        while(argv[1][i]!=' '&& argv[1][i]!='\0'){
            mask=mask*10+argv[1][i]-'0';
            i++;
        }
        int num=0;
        i=0;
        while(argv[2][i]!=' '&& argv[2][i]!='\0'){
            num=num*10+argv[2][i]-'0';
            i++;
        }
        if(strcmp(argv[0],"taskset")==0){
            int pid = sys_spawn(test_tasks[num],NULL,ENTER_ZOMBIE_ON_EXIT);
            sys_taskset(mask,pid);
        }else
            printf("Unknown command!\n");
    }else if(argc == 4){
        if(strcmp(argv[0],"taskset")==0){
            int mask = 0;
            int i=0;
            while(argv[2][i]!=' '&& argv[2][i]!='\0'){
                mask=mask*10+argv[2][i]-'0';
                i++;
            }
            i=0;
            int pid=0;
            while(argv[3][i]!=' '&& argv[3][i]!='\0'){
                pid=pid*10+argv[3][i]-'0';
                i++;
            }
            sys_taskset(mask,pid);
        }else
            printf("Unknown command!\n"); 
    }
    else if(argc != 0)
        printf("Unknown command!\n");
    /*screen_cursor_y-=2;
    printf("                                 \n");
    printf("                                 \n");
    screen_cursor_y-=2;*/
}

int read_to_buffer(char argv[][20]){
    char buffer[400];
    char c;
    int i=0,k=0;
    int argc=0;
    while(1){
        c=sys_get_char();
        if(c==(char)-1||(i==0&&(c==8||c==127)))
            continue;
        else if(c==8||c==127){
            i--;
            int cursor_x = sys_getcursor(0);
            int cursor_y = sys_getcursor(1);
            sys_move_cursor(cursor_x-1,cursor_y);
        }
        else if(c=='\n'||c=='\r'){
            buffer[i++]=' ';
            buffer[i] = '\0';
            int j = 0;
            while(buffer[j] == ' ' && j < i)
                j++;
            for(argc = 0,k = 0; j < i; j++)
            {
                if(buffer[j] == ' ')
                {
                    argv[argc][k] = '\0';
                    argc++;
                    k = 0;
                    while(buffer[j] == ' ' && j < i)
                        j++;
                }
                argv[argc][k++] = buffer[j];
            }
            printf("\n");
            return argc;
        }else{
            buffer[i++]=c;
            printf("%c",c);
        }


    }
}
void test_shell()
{
    // TODO:
    sys_move_cursor(1, 20);
    printf("------------------- COMMAND -------------------\n");
    printf("> root@UCAS_OS: ");

    while (1)
    {
        // TODO: call syscall to read UART port
        char argv[20][20];
        int argc = read_to_buffer(argv);
        cmd_op(argc,argv);
        printf("> root@UCAS_OS: ");
        // TODO: parse input
        // note: backspace maybe 8('\b') or 127(delete)

        // TODO: ps, exec, kill, clear
    }
}
